#!/usr/bin/env python3
#

import pandas as pd 
import re
from datetime import date
from mytools.pdexcel import PandasExcel
#from pdexcel import PandasExcel

def calculate_age(born,base_date=date.today()):
    '''根据生日获取年龄。
    '''
    today = base_date#date.today()
    try:
        birthday = born.replace(year=today.year)
    except ValueError:
        # raised when birth date is February 29 
        # and the current year is not a leap year
        birthday = born.replace(year=today.year, day=born.day-1)
    if birthday > today:
        return today.year - born.year - 1
    else:
        return today.year - born.year

def get_age_by_idcard(idcardnum,base_date=date.today()):
    '''根据身份证号码获取年龄
    '''
    born = date(int(idcardnum[6:10]),int(idcardnum[10:12]),int(idcardnum[12:14]))
    age = calculate_age(born,base_date)
    return age

def trim_idcard(idcardnum):
    '''规范化身份证号码，去掉前后空格；从残疾证号中提取身份证号码。
    '''

    #如果末尾带有逗号，去掉
    new_str_gp = re.match(r'\D*(\d+[xX]?\d*).*',idcardnum)
    if not new_str_gp:
        raise ValueError('身份证号码：{}不规范！'.format(idcardnum))
    new_str = new_str_gp.group(1)
    if len(new_str) < 18:
        raise ValueError('身份证号码：{}不规范！'.format(idcardnum))
    

    #如果存在末尾代’x'的，调整为大写。
    if new_str[17] == 'x':
        return new_str[:17] + 'X'
    else:
        return new_str[:18]

class Population():
    '''处理人口数据的通用基类
    实现对人口数据表中，正常人口信息进行查询，迭代获取，可以用于扩展形成其它需要人口信息的处理的地方。
    '''
    def __init__(self,path,idcard_label='公民身份号码',name_label='姓名',family_num='户编号',member_relation_label='家庭关系',sheet_name=None,index_col=0,header=1):
        self.path = path
        if sheet_name:
            self.sheet_name = sheet_name
            self.pe = PandasExcel(path,sheet_name=sheet_name,index_col=index_col,header=header+1)
            self.data = self.pe.getPandasData()
            #self.data = pd.read_excel(path,sheet_name=sheet_name,index_col=index_col,header=header)
        else:
            self.pe = PandasExcel(path,index_col=index_col,header=header+1)
            self.data = self.pe.getPandasData()
            #self.data = pd.read_excel(path,index_col=index_col,header=header)
        self.data.fillna('None')
        self.id_label = idcard_label
        self.m_relation_label = member_relation_label
        self.name_label = name_label
        self.fm_num_label = family_num

        self.data[idcard_label] = self.data[idcard_label].astype('str')
        self.formatIdCard(self.data,idcard_label)

        self.getFamily()

        if not self.checkFamilyNumber():
            self.fm_num_counter = 1000
            self.data.insert(1,'户编号',None)
            self.createFamilyNum()

    def checkFamilyNumber(self):
        if '户编号' in self.data.columns:
            return True
        else:
            return False

    def getFamily(self):
        family_dict = {}
        family_id = None
        family_list = []
        everyone_id_set = set()
        
        for index,everone in self.data.iterrows():
            relation = everone[self.m_relation_label]
            #name = everone[self.name_label]
            idcard = everone[self.id_label] 
            everyone_id_set.add(idcard)

            if relation == '户主':
                if not family_id:
                    family_id = idcard
                else:
                    family_dict[family_id] = family_list
                    family_list = []
                    family_id = idcard
            family_list.append(everone)

        family_dict[family_id] = family_list

        self.family_dict = family_dict
        self.family_idset = set(self.family_dict.keys())
        self.everyone_id_set = everyone_id_set
        #print(len(self.family_idset))
        
    def searchByName(self,name):
        name = name.strip()

        find_people = self.data.loc[self.data[self.name_label] == name]
        return find_people

    def searchByIdCard(self,idcard):
        idcard = trim_idcard(idcard)
        if idcard not in self.everyone_id_set:
            return pd.DataFrame()
        find_people = self.data.loc[self.data[self.id_label] == idcard]
        if find_people.empty:
            raise ValueError('这里不应该产生异常！')
        return find_people
        
    def getFamilyIdSet(self):
        return self.family_idset

    def getEveryoneIdSet(self):
        return self.everyone_id_set

    def getFamilyNum(self,idcard):
        idcard = trim_idcard(idcard)
        if idcard not in self.everyone_id_set:
            return None
        else:
            find_fmnum = self.data.loc[self.data[self.id_label] == idcard]
            if find_fmnum.empty:
                raise ValueError('这里不应该产生异常！')
            return find_fmnum[self.fm_num_label].values[0]

    def createFamilyNum(self):
        self.fm_num_counter = 1000
        for owner_id,ever_fm in self.iterFamily():
            for member in ever_fm:
                #查找这个成员的位置
                m_id = member[self.id_label]
                #print(m_id)
                find_id = self.data.loc[self.data[self.id_label]==m_id]
                #写入编号
                if find_id.empty:
                    raise KeyError('身份证号：{}不应该找不到！'.format(m_id))
                self.data.loc[find_id.index.values[0],[self.fm_num_label]] = self.fm_num_counter
                #print(find_id.index.values[0])

            self.fm_num_counter += 1

    def iterFamily(self):
        for key in self.family_dict:
            yield key,self.family_dict[key]

    def iterEveryone(self):
        for index,everone in self.data.iterrows():
            yield index,everone

    def formatIdCard(self,df,idcard_item):
        new_id_card = df[idcard_item].apply(trim_idcard)
        df[idcard_item] = new_id_card

    def show(self):
        print(self.data.head())

    def save(self,path=None):
        if not path:
            path = self.path
        self.data.to_excel(path)


class PopulationSpecial(Population):
    '''主要处理人口信息中的存疑表
    读取方式和普通的人口信息读取方式一致，但是需要存疑表中自己建立【户编号】列，然后将单独的
    户编号以2000开始进行编号。
    通过单独调用createFamilyNum函数，程序会自动搜索普通人口信息，将非单独户中的户编号以对应
    的户上的编号填充，只需在第一次完善表时调用即可。
    这个类通过getFamilyIdSet或iterFamily获取的户信息是指所有的独立户的信息。
    这个类通过getEveryoneIdSet或iterEveryone获取的是所有存疑人员信息。
    '''
    def __init__(self,path,idcard_label='公民身份号码',name_label='姓名',family_num='户编号',member_relation_label='家庭关系',sheet_name='存疑人口',owner_id_card_laebel='户主身份证号',index_col=0,header=1):
        self.owner_id_card_laebel = owner_id_card_laebel
        Population.__init__(self,path,idcard_label,name_label,family_num,member_relation_label,sheet_name,index_col,header)

        
    def getFamily(self):
        family_dict = {}
        everyone_id_set = set()

        single_fm = self.data.loc[self.data[self.fm_num_label] >= 2000]
        if single_fm.empty:
            return None
        
        gp_fm = single_fm.groupby(self.data[self.fm_num_label])
        for fm_num,ever_fm in gp_fm:
            family_list = []
            family_id = None
            for index,everone in ever_fm.iterrows():
                relation = everone[self.m_relation_label]
                #name = everone[self.name_label]
                idcard = everone[self.id_label] 

                if relation == '户主':
                    if not family_id:
                        family_id = idcard
        
                family_list.append(everone)

            family_dict[family_id] = family_list

        self.family_dict = family_dict
        self.family_idset = set(self.family_dict.keys())

        #get everyone id set
        for index,everone in self.data.iterrows():
            idcard = everone[self.id_label] 
            everyone_id_set.add(idcard)

        self.everyone_id_set = everyone_id_set

    def createFamilyNum(self):
        #self.fm_num_counter = 1000
        pp = Population(self.path)

        for index,member in self.iterEveryone():
            print(self.fm_num_label)
            try:
                fm_num = member[self.fm_num_label]
            except KeyError:
                print('存疑人口表中，应当自己创建[户编号]列！')
            if pd.isnull(fm_num) :
                owner_id = member[self.owner_id_card_laebel]
                fm_num = pp.getFamilyNum(owner_id)
                if not fm_num:
                    print('查找{}失败！'.format(owner_id))
                else:
                    self.data.loc[index,[self.fm_num_label]] = fm_num


class PopulationEx():
    '''这个类用于扩展普通人口数据类，将存疑人口数据信息也包含了进来，方便使用
    这个类中相对固定我们获取数据的原文件的格式，就是正常人口和存疑人口构成的人口信息表。
    '''
    def __init__(self,path):
        self.normal_popu = Population(path)
        self.special_popu = PopulationSpecial(path)

    def getFamilyIdSet(self):
        return self.normal_popu.getFamilyIdSet().union(self.special_popu.getFamilyIdSet())

    def getEveryoneIdSet(self):
        return self.normal_popu.getEveryoneIdSet().union(self.special_popu.getEveryoneIdSet())

    def getFamilyNum(self,idcard):
        ret = self.normal_popu.getFamilyNum(idcard)
        if not ret.empty:
            return ret
        ret = self.special_popu.getFamilyNum(idcard)
        return ret

    def iterFamily(self):
        for key,value in self.normal_popu.iterFamily():
            yield key,value
        for key,value in self.special_popu.iterFamily():
            yield key,value
        #new_dict = dict(self.normal_popu.family_dict.items()+self.special_popu.family_dict.items())
        #for key in new_dict:
        #    yield key,new_dict[key]

    def iterEveryone(self):
        for index,everone in self.normal_popu.iterEveryone():
            yield index,everone
        for index,everone in self.special_popu.iterEveryone():
            yield index,everone

    def searchByName(self,name):
        ret = self.normal_popu.searchByName(name)
        if not ret.empty:
            return ret
        ret = self.special_popu.searchByName(name)
        return ret

    def searchByIdCard(self,idcard):
        ret = self.normal_popu.searchByIdCard(idcard)
        if not ret.empty:
            return ret
        ret = self.special_popu.searchByIdCard(idcard)
        return ret

    def show(self):
        self.normal_popu.show()
        self.special_popu.show()


if __name__ == '__main__':
    path = '大林村全村人口花名册20190818.xlsx'
    #pl = Population(path)
    pl = PopulationEx(path)
    pl.show()
    #fm = pl.getFamilyNum('621126201601172913')
    #print(fm)
    #pl.save('newtest.xlsx')
    #pl.checkFamilyNumber()
    fmid = pl.getFamilyIdSet()
    print(len(fmid))
    ever_id = pl.getEveryoneIdSet()
    print(len(ever_id))
    ret = pl.searchByIdCard('621126201601172913')
    if not ret.empty:
        print(ret)
    else:
        print('not found')
    ret = pl.searchByIdCard('621126201601172923')
    if not ret.empty:
        print(ret)
    else:
        print('not found')

    ret = pl.searchByName('卢英俊')
    if not ret.empty:
        print(ret)
    else:
        print('not found')
    ret = pl.searchByName('卢社生')
    if not ret.empty:
        print(ret)
    else:
        print('not found')

